package com.tjf.ioc_annotation_lib;

import android.view.View;

import com.tjf.ioc_annotation_lib.annation.BindView;
import com.tjf.ioc_annotation_lib.annation.Click;
import com.tjf.ioc_annotation_lib.annation.ContentView;
import com.tjf.ioc_annotation_lib.annation_common.onBaseCommon;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author: tjf
 * @date: 2023-05-31
 * @desc：
 */
public class InjectTool {
    public static final String TAG = InjectTool.class.getSimpleName();


    public static void inject(Object object) {
        injectSetContentView(object);
        injectBindView(object);
//        injectClickView(object);
        injectEvent(object);
    }

    /**
     * 把布局绑定到acitivity中去
     *
     * @param object acitivity中的 this
     */
    private static void injectSetContentView(Object object) {
        Class<?> mActivityClass = object.getClass();
        //获取注解@ContentView 注解
        ContentView mContentView = mActivityClass.getAnnotation(ContentView.class);
        if (null == mContentView) {

            return;
        }
        //mContentView 得到value 布局id
        int layoutId = mContentView.value();
        if (-1 == layoutId) {
            return;
        }
        try {
            // 反射执行setContentView 方法
            Method setContentViewMethod = mActivityClass.getMethod("setContentView", int.class);
            // 通过Method 执行setContentView
            setContentViewMethod.invoke(object, layoutId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //进行绑定
    }

    /**
     * 把控件和id 进行绑定 赋值
     *
     * @param object acitivity中的 this
     */
    private static void injectBindView(Object object) {
        Class<?> mActivityClass = object.getClass();
        //获取 所有的Field  数组
        Field[] mFields = mActivityClass.getDeclaredFields();//字段 私有的  公开的修饰 都可以
        for (Field mField : mFields) {
            mField.setAccessible(true);//让jam 不要去管private 修饰的字段
            //获取 BindView 注解
            BindView mBindView = mField.getAnnotation(BindView.class);
            if (null == mBindView) {
                continue;
            }
            //BindView 得到value 字段id
            int viewId = mBindView.value();
            if (-1 == viewId) {
                continue;
            }
            try {
                // 反射执行findViewById 方法
                Method findViewByIdMethod = mActivityClass.getMethod("findViewById", int.class);
                // 通过Method 执行findViewById
                Object resultView = findViewByIdMethod.invoke(object, viewId);
                // 获取反射的值 赋值给控件
                mField.set(object, resultView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 把控件和id 进行绑定 赋值
     *
     * @param object acitivity中的 this
     */
    private static void injectClickView(final Object object) {
        Class<?> mActivityClass = object.getClass();
        //获取 所有的Method  数组
        Method[] mDeclaredMethods = mActivityClass.getDeclaredMethods();//字段 私有的  公开的修饰 都可以
        for (final Method mDeclaredMethod : mDeclaredMethods) {
            mDeclaredMethod.setAccessible(true);//让jam 不要去管private 修饰的字段
            //获取 BindView 注解
            Click mClick = mDeclaredMethod.getAnnotation(Click.class);
            if (null == mClick) {
                continue;
            }
            //BindView 得到value 字段id
            int viewId = mClick.value();
            if (-1 == viewId) {
                continue;
            }
            try {
                // 反射执行findViewById 方法
                Method findViewByIdMethod = mActivityClass.getMethod("findViewById", int.class);
                // 通过Method 执行findViewById
                Object resultView = findViewByIdMethod.invoke(object, viewId);
                // 强制转换  后执行setOnClickListener
                View view = (View) resultView;
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //反射回调到Click 注解的函数中
                        try {
                            mDeclaredMethod.invoke(object);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 兼容所有事件
     *
     * @param object acitivity中的 this
     */
    private static void injectEvent(final Object object) {
        Class<?> mActivityClass = object.getClass();
        //获取 所有的Method  数组
        Method[] mDeclaredMethods = mActivityClass.getDeclaredMethods();// 方法 都可以
        for (final Method mDeclaredMethod : mDeclaredMethods) {
            mDeclaredMethod.setAccessible(true);//让jam 不要去管private 修饰的字段
            //获取  所有的事件的注解数
            Annotation[] mAnnotations = mDeclaredMethod.getAnnotations();
            for (Annotation mAnnotation : mAnnotations) {
                Class<? extends Annotation> annotationType = mAnnotation.annotationType();
                onBaseCommon baseCommon = annotationType.getAnnotation(onBaseCommon.class);
                if (null == baseCommon) {
                    continue;
                }
                // 获取事件三要素
                String setCommonListener = baseCommon.setCommonListener();
                Class setCommonObjectListener = baseCommon.setCommonObjectListener();
                String callbackMethod = baseCommon.callbackMethod();// 在多个方法下才有用
                //动态代理
                try {
                    Method valueMethod = annotationType.getDeclaredMethod("value");//获取注解中value方法
                    int[] values = (int[]) valueMethod.invoke(mAnnotation);//  获取需要注册的控件
                    for (int value : values) {
                        //通过反射获取findViewById方法
                        Method findViewByIdMethod = mActivityClass.getMethod("findViewById", int.class);
                        // 通过Method 执行findViewById
                        Object resultView = findViewByIdMethod.invoke(object, value);
                        // 再次启用反射 拿到setCommonListener 的事件订阅 设置回调
                        Method mViewMethod = resultView.getClass().getMethod(setCommonListener, setCommonObjectListener);
                        //动态代理 监听 第三个要素
                        Object proxy = Proxy.newProxyInstance(setCommonObjectListener.getClassLoader(),//动态代理内部需要的getClassLoader
                                new Class[]{setCommonObjectListener},// 动态代理 只监听 第二要素 的接口
                                new InvocationHandler() {
                                    @Override
                                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                                        return mDeclaredMethod.invoke(object, null);
                                    }
                                }
                        );
                        // 事件三要素  最终的事件消费 设置监听
                        mViewMethod.invoke(resultView, proxy);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
